#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/consumer.h>
#include <linux/iio/events.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/of.h>  
#include <linux/property.h> 


#define SENSOR_ADDR 0x40  // 假设传感器的 I2C 地址为 0x40

MODULE_LICENSE("GPL");

struct i2c_sensor_data {
    struct i2c_client *client;
	struct iio_dev *indio_dev;  // IIO 设备结构
	
    int temperature;   // 温度值
    int humidity;      // 湿度值
};

static int i2c_sensor_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask);


// IIO 设备通道定义
static const struct iio_chan_spec i2c_sensor_channels[] = {
    {
        .type = IIO_TEMP,	// 温度通道
        .indexed = 1,		//索引值为0
        .channel = 0,		//温度通道编号为0
        .address = 0,		// 寄存器地址
        .scan_type = IIO_SINGLE_ENDED,  // 单端采样模式
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),// 使能原始读写
    },

	 {
        .type = IIO_HUMIDITYRELATIVE,	// 湿度通道
        .indexed = 1,			//索引值为0
        .channel = 1,			//温度通道编号为1
        .address = 1,			// 寄存器地址
        .scan_type = IIO_SINGLE_ENDED,  			 // 单端采样模式
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),// 使能原始读写
    },
    // 其他通道可以在这里定义
    IIO_CHAN_END// 结束标记
};

// 设备信息结构
static const struct iio_info i2c_sensor_info = {
    .read_raw = i2c_sensor_read_raw,		// 读取原始数据
};

// I2C 读取传感器数据的函数
static int i2c_sensor_read_data(struct i2c_client *client, int *temperature, int *humidity) {
    u8 buf[4];  // 假设传感器返回 4 字节数据，2 字节为温度，2 字节为湿度
    int ret;

    ret = i2c_smbus_read_i2c_block_data(client, SENSOR_ADDR, sizeof(buf), buf);
    if (ret < 0) {
        dev_err(&client->dev, "Failed to read sensor data from sensor\n");
        return ret;
    }

	//数据有效性检查
	if(buf[0] == 0xFF || buf[1] == 0xFF || buf[2] == 0xFF || buf[3] == 0xFF)
	{
		dev_warn(&client->dev, "Invalid humidity reading\n");
		return -EINVAL;
	}

    // 解析传感器返回的数据
    *temperature = ((s16)((buf[0] << 8) | buf[1])) / 10;
    *humidity = ((s16)((buf[2] << 8) | buf[3])) / 10;

    return 0;
}

// IIO 驱动的读数据函数
static int i2c_sensor_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) {
    struct i2c_sensor_data *data = iio_priv(indio_dev);
    int ret;

    switch (mask) {
    case IIO_CHAN_INFO_RAW:
        switch (chan->type) 
		{
			case IIO_TEMP:
	            ret = i2c_sensor_read_data(data->client, &data->temperature, &data->humidity);
	            if (ret)
	                return ret;
	            *val = data->temperature;
	            return IIO_VAL_INT;
			
        	case IIO_HUMIDITYRELATIVE:
	            ret = i2c_sensor_read_data(data->client, &data->temperature, &data->humidity);
	            if (ret)
	                return ret;
	            *val = data->humidity;
	            return IIO_VAL_INT;
			default:
				return -EINVAL;
        }
	case IIO_CHAN_INFO_SCALE:
		*val = 1;
		*val2 = 10;
        return IIO_VAL_FRACTIONAL;
    default:
        return -EINVAL;
    }
}


// IIO 驱动的 probe 函数
static int i2c_sensor_probe(struct i2c_client *client, const struct i2c_device_id *id) {
    struct i2c_sensor_data *data;
    struct iio_dev *indio_dev;
    int ret;

	//检查I2C通信是否正常
	if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
	{
		dev_err(&client->dev,"I2C functionality check failed\n");
		return -ENODEV;
	}

    // 分配 IIO 设备结构
    indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    if (!indio_dev)
        return -ENOMEM;

    data = iio_priv(indio_dev);
    data->client = client;
    i2c_set_clientdata(client, data);

    // 初始化 IIO 设备
    indio_dev->dev.parent = &client->dev;
    indio_dev->info = &i2c_sensor_info;
    indio_dev->channels = i2c_sensor_channels;
    indio_dev->num_channels = ARRAY_SIZE(i2c_sensor_channels);
    indio_dev->name = "i2c_sensor";
    indio_dev->modes = INDIO_DIRECT_MODE;

    // 注册 IIO 设备
    ret = iio_device_register(indio_dev);
    if (ret)
    {	
    	dev_err(&client->dev, "Failed to register IIO device: %d\n", ret);
        return ret;
    }

    data->indio_dev = indio_dev;

	dev_info(&client->dev, "I2C sensor driver probed successfully\n");
    return 0;
}


// IIO 驱动的 remove 函数
static int i2c_sensor_remove(struct i2c_client *client) 
{
    struct i2c_sensor_data *data = i2c_get_clientdata(client);

    iio_device_unregister(data->indio_dev);
    return 0;
}

static const struct i2c_device_id i2c_sensor_id[] = {
    { "i2c_sensor", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, i2c_sensor_id);

static const struct of_device_id i2c_sensor_of_match[] = {
	{.compatible = "vendor, sensor-name"},
	{ /* sentinel */ }
};

MODULE_DEVICE_TABLE(of, i2c_sensor_of_match);


static struct i2c_driver i2c_sensor_driver = {
    .driver = {
        .name   = "i2c_sensor",
        .owner  = THIS_MODULE,
        .of_match_table = i2c_sensor_of_match,
    },
    .probe      = i2c_sensor_probe,
    .remove     = i2c_sensor_remove,
    .id_table   = i2c_sensor_id,
};

static int __init i2c_sensor_driver_init(void)
{
    return i2c_add_driver(&i2c_sensor_driver);
}

static void __exit i2c_sensor_driver_exit(void)
{
    i2c_del_driver(&i2c_sensor_driver);
}

module_init(i2c_sensor_driver_init);
module_exit(i2c_sensor_driver_exit);
